<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>飞机大战</title>
</head>
<body>
<div id="stage" style="width: 480px;height: 650px;margin: 0px auto;">
    <canvas id="canvas" width="480px" height="650px"></canvas>
</div>
<script>


    //定义宽和高
    var WIDTH=480,HEIGHT=650;
    var score=0,life=3;
    //定义状态
    var START= 0,
            STARTING= 1,
            RUNNING= 2,
            PAUSE= 3,
            GAME_OVER=4;
    /**
     *state表示游戏的状态
     */
    var state=START;

    //获取数据
    var canvas=document.getElementById("canvas");
    ctx=canvas.getContext("2d");

    /***
     * 创建图像对象用来表示天空,英雄,敌人,版权
     */
    var bg=new Image();
    bg.src="img/background.png";

    var copyright=new Image();
    copyright.src="img/shoot_copyright.png";

    var pause=new Image();
    pause.src="img/game_pause_nor.png";

    var l = [];
    l[0] = new Image();
    l[0].src="img/game_loading1.png";
    l[1] = new Image();
    l[1].src="img/game_loading2.png";
    l[2] = new Image();
    l[2].src="img/game_loading3.png";
    l[3] = new Image();
    l[3].src="img/game_loading4.png";
    //创建英雄图像数组
    var h = [];
    h[0] = new Image();
    h[0].src="img/hero1.png";
    h[1] = new Image();
    h[1].src="img/hero2.png";
    h[2] = new Image();
    h[2].src="img/hero_blowup_n1.png";
    h[3] = new Image();
    h[3].src="img/hero_blowup_n2.png";
    h[4] = new Image();
    h[4].src="img/hero_blowup_n3.png";
    h[5] = new Image();
    h[5].src="img/hero_blowup_n4.png";
    //创建子弹图像
    var b = new Image();
    b.src="img/bullet1.png";
    //创建小飞机图像数组
    var e1=[];
    e1[0]=new Image();
    e1[0].src="img/enemy1.png";
    e1[1]=new Image();
    e1[1].src="img/enemy1_down1.png";
    e1[2]=new Image();
    e1[2].src="img/enemy1_down2.png";
    e1[3] = new Image();
    e1[3].src="img/enemy1_down3.png";
    e1[4] = new Image();
    e1[4].src="img/enemy1_down4.png";

    //创建中型飞机图像数组
    var e2=[];
    e2[0]=new Image();
    e2[0].src="img/enemy2.png";
    e2[1] = new Image();
    e2[1].src="img/enemy2_down1.png";
    e2[2] = new Image();
    e2[2].src="img/enemy2_down2.png";
    e2[3] = new Image();
    e2[3].src="img/enemy2_down3.png";
    e2[4] = new Image();
    e2[4].src="img/enemy2_down4.png";

    //创建大型飞机图像数组
    var e3=[];
    e3[0] = new Image();
    e3[0].src="img/enemy3_n1.png";
    e3[1] = new Image();
    e3[1].src="img/enemy3_n2.png";
    e3[2] = new Image();
    e3[2].src="img/enemy3_down1.png";
    e3[3] = new Image();
    e3[3].src="img/enemy3_down2.png";
    e3[4] = new Image();
    e3[4].src="img/enemy3_down3.png";
    e3[5] = new Image();
    e3[5].src="img/enemy3_down4.png";
    e3[6] = new Image();
    e3[6].src="img/enemy3_down5.png";
    e3[7] = new Image();
    e3[7].src="img/enemy3_down6.png";


    //数据对象
    var SKY={image:bg,width:480,height:650,speed:20}; //50ms
    var LOADING={frames:l,width:186,height:38,x:0,y:HEIGHT-38,speed:5}; //200ms
    //刷新频率越快，捕获鼠标坐标的延迟就越小，鼠标与飞机同步移动的卡顿越小
    var HERO={frames:h,baseFrameCount:2,width:99,height:124,speed:100}; //10ms
    var BULLET={image:b,width:9,height:21};

    //层级结构 ： 对象集合--》图片对象--》图像数组
    var E1={type:1,score:1,frames:e1,baseFrameCount:1,life:1,minSpeed:70,maxSpeed:100,width:57,height:51};

    var E2={type:2,score:5,frames:e2,baseFrameCount:1,lift:5,minSpeed:50,maxSpeed:70,width:69,height:95};

    var E3={type:3,score:5,frames:e3,baseFrameCount:2,life:20,speed:10,width:169,height:258};


    //保存有hero发射的所有子弹
    var bullets=[];
    var enemies=[];

    //gezhong事件
    //为canvas添加事件(onclick ,onmousemove,onmouseout)
    canvas.onclick=function(){
        if(state==START)
            state=STARTING;
    }

    /**
     * 鼠标移动事件 处理hero与鼠标的位置
     * */
    canvas.onmousemove=function(e){
        var x= e.offsetX;
        var y= e.offsetY;

        hero.x=x-HERO.width/2;
        hero.y=y-HERO.height/2;

    }
    canvas.onmouseout=function(e){
        if(state==RUNNING)
        {
            state=PAUSE;
        }
    }

    canvas.onmouseover=function(e){
        if(state==PAUSE){
            state=RUNNING;
        }
    }


    ////////////业务对象

    /**
     * 敌人飞机包括 大中小 型
     * */
    var Enemy=function(config){
        this.score=config.score;//分数
        this.frames=config.frames;//图像列表
        this.frame=null;  //当前显示的图像
        this.frameIndex=0;//当前显示的图像索引累加值
        this.baseFrameCount=config.baseFrameCount;

        //横纵坐标
        this.x=Math.ceil(Math.random()*(WIDTH-config.width));

        this.y=-config.height;

        this.type=config.type;
        this.speed=0;
        //中小型飞机
        if(config.minSpeed&&config.maxSpeed){
            this.speed=1000/(Math.random()*(config.maxSpeed-config.minSpeed)+config.minSpeed);
        }else{
        //大型飞机
            this.speed=1000/config.speed;
        }

        this.lastTime=0;
    }
    /**
     * 检查时间是否到期
     * */
    Enemy.prototype.timeInterval=function(){
        var currentTime=new Date().getTime();
        if(currentTime-this.lastTime>=this.speed){
            this.lastTime=new Date().getTime();
            return true;
        }
        return false;
    }
    Enemy.prototype.step=function(){
        if(this.timeInterval()){
            //基本图像切换
            this.frame=this.frames[this.frameIndex%this.baseFrameCount];
            this.frameIndex++;
            //飞机移动
            this.move();
        }
    }
    Enemy.prototype.move=function(){
        //飞机移动
        this.y++;
    }
    Enemy.prototype.paint=function(){
        //绘制飞机图像
        ctx.drawImage(this.frame,this.x,this.y);
    }
    //判断当前飞机是否超出canvas边界
    Enemy.prototype.outOfBounds=function(){
        if(this.y>HEIGHT){
            return true;
        }
        return false;
    }
    //判断敌人是否与其他物体碰撞 , c:可以是英雄，可以是子弹
     Enemy.prototype.hit=function(c){
         //c的中心点坐标
         var cX= c.x+ c.width/2;
         var cY= c.y+ c.height/2;

         var leftStart=this.x- c.width/2;
         var leftEnd=this.x+this.width+ c.width/2;

         var topStart=this.y- c.height/2;
         var topEnd=this.y+this.height+ c.height/2;

         var result=leftStart<cX&&cX<leftEnd&&topStart<cY&&cY<topEnd;
         return result;
     }

    //当敌人飞机与其他元素碰撞时的操作方法
    Enemy.prototype.duang=function(){
        //生命减少
        this.life--;
        if(this.life==0){
            //切换到爆破状态
            this.down=true;
            score+=this.score;
            this.frameIndex=this.baseFrameCount;
        }
    }


    /**
     * 子弹对象
     */

    var Bullet=function(config,x,y){
        this.width=config.width;
        this.height=config.height;
        this.frame=config.image;
        this.x=x;
        this.y=y;
        this.canDelete=false;//是否删除子弹，默认为否
//        this.move=function(){
//            this.y-=2;
//        }
//        this.paint=function(){
//            ctx.drawImage(this.frame,this.x,this.y);
//        }
    }
    Bullet.prototype.move=function(){
        this.y-=2;
    }
    Bullet.prototype.paint=function(){
        ctx.drawImage(this.frame,this.x,this.y);
    }
    //子弹是否越界
    Bullet.prototype.outOfBounds=function(){
        return this.y<-this.height;
    }
    //子弹与敌人飞机碰撞时的操作
    Bullet.prototype.duang=function(){
        this.canDelete=true;
    }


    /*
     *
     * 创建飞机业务对象
     */

    var Hero=function(config){
        this.frames=config.frames;
        this.frameIndex=0;
        this.baseFrameCount=config.baseFrameCount;
        this.width=config.width;
        this.height=config.height;
        this.speed=1000/config.speed;
        this.lastTime=0;
        this.x=(WIDTH-this.width)/2;
        this.y=HEIGHT-this.height-30;

        this.shootLastTime=0;
        //发送子弹的间隔 数字
        this.shootInterval=200;

    }
    Hero.prototype.step=function(){
        var currentTime=new Date().getTime();
        if(currentTime-this.lastTime>=this.speed){
            this.frame=this.frames[this.frameIndex%this.baseFrameCount];
            this.frameIndex++;
            this.lastTime=new Date().getTime();
        }
    }
    Hero.prototype.paint=function(){
        ctx.drawImage(this.frame,this.x,this.y);
    }
    //处理子弹的发射
    Hero.prototype.shoot=function(){
        var currentTime=new Date().getTime();
        if(currentTime-this.shootLastTime>=this.shootInterval){
            //到达时间间隔，可以发射子弹
            var bullet=new Bullet(BULLET,this.x+45,this.y);
            //数组的下标从0开始，此时长度为1，所以数组的长度永远会比下标多1
            //bullets[bullets.length]永远会自增1；

            //越出屏幕上边界的子弹已被删除
//            if(bullets.length>=50)
//            {
//                //注释：请注意，splice() 方法与 slice() 方法的作用是不同的，splice() 方法会直接对数组进行修改。
//
//                //slice() 方法可从已有的数组中返回选定的元素。
//                //http://www.w3school.com.cn/jsref/jsref_slice_array.asp
//                // bullets.slice(0,25);
//                //  bullets.length=25;
//
//                //splice() 方法向/从数组中添加/删除项目，然后返回被删除的项目。
//               // 注释：该方法会改变原始数组。
//                //http://www.w3school.com.cn/jsref/jsref_splice.asp
//                bullets.splice(0,25);
//            }


            bullets[bullets.length]=bullet;
           // console.log("子弹数量："+bullets.length);
            this.shootLastTime=new  Date().getTime();
        }
    }
    /**
     * 天空的业务对象
     * */
    var Sky=function(config){
        this.bg=config.image;
        this.width=config.width;
        this.height=config.height;
        this.speed=1000/config.speed;
        this.x1=0;
        this.y1=0;
        this.x2=0;
        this.y2=-this.height;
        this.lastTime=0; //上一次执行动作时间的毫秒数
    }
    /**
     * 移动背景纵坐标
     * */
    Sky.prototype.step=function(){
            //判断是否到达天空移动的时间
            //获取当前时间的毫秒数
           var currentTime=new Date().getTime();
            if(currentTime-this.lastTime>=this.speed){
                this.y1++;
                this.y2++;
                this.lastTime=new Date().getTime();
               // console.log(this.y1+" : "+this.y2);

            }
            //判断y1,y2是否超出范围
            if(this.y1>=this.height){
                this.y1=-this.height;
            }
            if(this.y2>=this.height){
                this.y2=-this.height;
            }

    }
    /**
     * 绘制天空图像
     * */
    Sky.prototype.paint=function(ctx){
        ctx.drawImage(this.bg,this.x1,this.y1);
        ctx.drawImage(this.bg,this.x2,this.y2);
    }
    /**
     * 加载业务对象
     * config：表示加载的数据对象
     * */
    var Loading=function(config){
        this.speed=1000/config.speed;
        this.lastTime=0;
        this.frame=null;
        this.frameIndex=0;
        //更换loading图像
        this.step=function(){
            var currentTime=new Date().getTime();
            if(currentTime-this.lastTime>this.speed){
                //获取不同的图像config.frames中的元素给frame
                this.frame=config.frames[this.frameIndex];
                this.frameIndex++;
                if(this.frameIndex>=4){
                    //更新状态
                    state=RUNNING;
                }
                this.lastTime=new Date().getTime();
            }
        }
        /**
         * 绘制不同的图像到canvas上
         * */
        this.paint=function(ctx){
            ctx.drawImage(this.frame,config.x,config.y);
        }
    }

    //创建业务对象
    var sky=new Sky(SKY);
    var loading=new Loading(LOADING);
    var hero=new Hero(HERO);


    /**
     * 检查 敌人是否与子弹或英雄碰撞
     * */
    function checkHit(){
        for(var i=0;i<enemies.length;i++){
            var enemy=enemies[i];
            if(enemy.down||enemy.canDelete){
                continue;
            }
            //与子弹相比较
            for(var j=0;j<bullets.length;j++){
                var bullet=bullets[i];
                console.log(bullet)
                //进行比较
//                if(enemy.hit(bullet)){
//                    enemy.duang();
//                    bullet.duang();
//                }
            }
        }
    }

    //删除多余组件
    function deleteComponent(){
        //删除超出下边界的小飞机
        for(var i=0;i<enemies.length;i++){
            if(enemies[i].outOfBounds())
            {
                enemies.splice(i,1);
            }
        }
      //  console.log("删除超出下边界的小飞机:"+enemies.length);
        //删除超出上边界的子弹
        for(var i=0;i<bullets.length;i++){
            if(bullets[i].outOfBounds()||bullets.canDelete){
                bullets.splice(i,1);
            }
        }
       // console.log("删除超出上边界的子弹:"+bullets.length);
    }

    //创建敌人飞机的数据
    var lastTime=new Date().getTime();
    var interval=800;

    /**
     * 根据指定时间差创建不同类型的敌人飞机
     * 将创建好的飞机保存到enmeies 数组中
     * */
    function componentEnter(){
        var currentTime=new Date().getTime();
        if(currentTime-lastTime>=interval){
            //0~9
            var n=Math.floor(Math.random()*10);
            if(n>=0&&n<=6){
                //创建小型飞机
                enemies[enemies.length]=new Enemy(E1);
            }
            else if(n>=7&&n<=8){
                //创建中型飞机
                enemies[enemies.length]=new Enemy(E2);
            }
            else{
                //创建大型飞机
                //如果数组中第一个元素不是大型飞机，则创建一个，并且放在第一个元素的位置，其他飞机位置后移
                if(enemies[0].type!=3){
                    enemies.splice(0,0,new Enemy(E3));
                }
            }
            lastTime=new Date().getTime();
        }
    }


    /**
     * 绘制各个组件
     * */
    function paintComponent(){
        //绘制子弹
        for(var i=0;i<bullets.length;i++){
            var bullet=bullets[i];
            bullet.paint();
        }

        for(var i=0;i<enemies.length;i++){
            var enemie=enemies[i];
            enemie.paint();
        }
        //
        //将绘制hero的方法移动至此
        hero.paint();
        ctx.font="20px 微软雅黑";
        ctx.fillText("SCORE:"+score,10,20);
        ctx.fillText("LIFE:"+life,400,20);
    }

    /**
     * 让所有的子弹（组件） 动起来（更新y坐标）
     * */
    function stepComponent(){
        for(var i=0;i<bullets.length;i++){
            bullets[i].move();
        }
        for(var i=0;i<enemies.length;i++){
            enemies[i].step();
        }
    }


    //定时器，固定刷新频率为 1000/100 =10ms
    setInterval(function(){
        switch (state){
        case START:
            //天空在移动
            sky.step();
            sky.paint(ctx);
            //绘制copyright
            var x=(WIDTH-copyright.naturalWidth)/2;
            var y=(HEIGHT-copyright.naturalHeight)/2;
            ctx.drawImage(copyright,x,y);
            break;
            case STARTING:
                //准备开始
                sky.step();
                sky.paint(ctx);
                loading.step();
                loading.paint(ctx);
                break;
            case RUNNING:
                //游戏进行
                sky.step();
                sky.paint(ctx);

                hero.step();
                hero.paint(ctx);
                hero.shoot();


                checkHit();
                //添加新的组件 （敌人的小飞机）
                componentEnter();
                  //  console.log("敌机数量："+enemies.length);

                stepComponent();
                //删除屏幕外的敌机
                deleteComponent();

                //绘制所有的组件
                paintComponent();

                break;
            case PAUSE:
                //暂停
                sky.step();
                sky.paint(ctx);

                paintComponent();
                ctx.drawImage(pause,(WIDTH-pause.width)/2,(HEIGHT-pause.height)/2);
                break;
            case GAME_OVER:
                break;
        }
    },1000/100)








































































</script>
</body>
</html>